<?php
ArrowController::importModel( "templatesSystem.templates.ArrowTemplateDescriptor" );
/**
 * Arrow template structure
 * 
 * @version 1.0
 * @license  GNU GPL
 * @author Artur Kmera <artur.kmera@arrowplatform.org> 
 */
class ArrowTemplatesStructure implements IArrowCacheable, IArrowSingleton{

	/**
	* Configuration from cache provider
	* 
	* @var Array
	*/
	private $configuration;

	/**
	 * Templates Structure instance
	 * 
	 * @var TemplateList[]
	 */
	private static  $selfInstances = null;

	/**
	 * Project reference
	 * 
	 * @var ArrowProject
	 */
	private $projectReference;


	/**
	 * Singleton !NO_REMOTE
	 * 
	 * @param ArrowProject $$projectReference
	 * @return ArrowTemplatesStructure Default instance
	 */
	public static function getDefault(  ) {
		if ( self::$selfInstances == null ) {
			self::$selfInstances = new ArrowTemplatesStructure( );
		}
		return self::$selfInstances ;
	}
	
	/**
	 * Constructor !NO_REMOTE
	 * 
	 * @param Integer $projectId Project Id.
	 */
	private function __construct(  ) {
		$this->projectReference = ArrowController::getDefault()->getProject();
		$this->sourcesDir = ArrowProject::PATH."/templates";
		$confFile = ArrowProject::PATH . "/" . ArrowProject :: TEMPLATES_CONF;
		
		$cacheFile = ArrowCacheProvider::getFileCache( $this, $confFile, array( "file_prefix" => "templates_structure" ) );
		
		require_once $cacheFile;
		$this->configuration = $cache;
	}
	
	/**
	 * IArrowCacheable implementation
	 *
	 * @param Array $params
	 * @return Array
	 */
	public function generateCache($params){
		$tmp = array();
		$conf = $this->projectReference->getXMLConfig(ArrowProject::TEMPLATES_CONF);
		$tmp["templates"] = $this->parseTemplatesDocument($conf);
		
		/*$packagesConf = $this->projectReference->getPackagesConf();
		foreach($packagesConf as $id => $package){
			$file = $package["dir"]."/templates-list.xml";
			if(file_exists($file)){
				$templates = $this->parseTemplatesDocument(simplexml_load_file($file), $id);
				$tmp["templates"] = array_merge( $tmp["templates"], $templates );		
			}
		}*/
		
		return $tmp;
	}
	
	private function parseTemplatesDocument($confDocument, $idPackage = ""){
		$parsed = array();
		foreach( $confDocument->templates->template as $template ){
			$tmpTemplate = array();
			$tmpTemplate["name"] = (string) $template["name"];
			$tmpTemplate["path"] = (string) $template["path"];
			$tmpTemplate["description"] = (string) $template["description"];
			if($idPackage)
				$tmpTemplate["package"] = $idPackage;
			$parsed[ $idPackage.$template["id"] ] = $tmpTemplate;
		}
		return $parsed;
	}
	
	/**
	 * Returns project reference
	 *
	 * @return ArrowProject
	 */
	public function getProject(){
		return $this->projectReference;
	}

	/**
	 * Returns all templates
	 *
	 * @return ArrowTemplateDescriptor[]
	 */
	public function getTemplates(){
		$templates = array();
		foreach( $this->configuration["templates"] as $id => $template ){
			$templates[] = $this->getTemplateById($id);
		}
		
		return $templates;
	}
	
	/**
	 * Returns template by id
	 * 
	 * @param integer $templateId Template id
	 * @return ArrowTemplateDescriptor
	 */
	public function getTemplateById( $templateId ){
		
		if (!isset ($this->configuration["templates"][$templateId]))
			throw new ArrowTemplatesException(array (
					"msg" => "Template dosn't exists !.",
					"id" => $templateId
					));
		$registred = $this->configuration["templates"][$templateId];
		$template = new ArrowTemplateDescriptor($this, $templateId, $registred["name"],  $this->sourcesDir . $registred["path"], $registred["description"]);
		return $template;
	}
	
	/**
	 * Return default template
	 *
	 * @todo wyeliminowa� instancje routera ( poniewa� pobierane jest w czasie startu routera getDefault go zap�tla ) 
	 * @return ArrowTemplateDescriptor
	 */
	public function getDefaultTemplate(  ){
		$result = 0;
		$mappinPath = ArrowController::getDefault()->getProject()->getSetting("arrow.default_template");
		$result = $this->getTemplateByMappingPath($mappinPath);
	if (empty ($result))
				throw new ArrowTemplatesException(array (
				"msg" => "Can't find default template!",
				));
		return $result;
	}
	
	/**
	 * Return template by mapping path
	 *
	 * @param string $path
	 * @return ArrowTemplateDescriptor
	 */
	public function getTemplateByMappingPath($path){
		$tmp = explode( "::", $path );
		$condiions = array( "path" => $tmp[0], "name" => $tmp[1] );
		return $this->findTemplate( $condiions );
	}

	/**
	 * Returns template ID by mapping path
	 *
	 * @param unknown_type $path
	 * @return unknown
	 */
	public function getTemplateIdByMappingPath($path){
		$tmp = explode( "::", $path );
		$args = array( "path" => $tmp[0], "name" => $tmp[1] );
		foreach( $this->configuration["templates"] as $id => $template ){
			if(
				$args["name"] == $template["name"] &&
				$args["path"] == $template["path"]
			)
				return $id;
		}
		
		throw new ArrowTemplatesException(array (
			"msg" => "Template dosn't exists !.",
			"mapping path" => $path
		));
	}
	
	/**
	 * finding template by parameters
	 *
	 * @param String[] $args
	 * @param boolean $onlyId If we don't whant to load whole TemplateDescriptor object and id is only thing we need
	 * @return ArrowTemplateDescriptor
	 */
	public function findTemplate( $args ){

		$result = false ;
		
		foreach( $this->configuration["templates"] as $id => $template ){
			if(
				$args["name"] == $template["name"] &&
				$args["path"] == $template["path"]
			){
				$result = $id;
				break;
			}
		}

		if ( $result === false )
				throw new ArrowTemplatesException(array (
				"msg" => "Template dosn't exists !.",
				"args" => print_r( $args, 1 )
				));
		return $this->getTemplateById($result);
	}

    public function createTemplate($mappingPath, $schemaId){
        if(!preg_match("/\/.+::.+/", $mappingPath))
            throw new ArrowTemplatesException(array (
    			"msg" => "Wrong path format !.",
    			"mapping path" => $mappingPath
    		));
            	
        try{
            $template = $this->getTemplateIdByMappingPath($mappingPath);
            
            if($template){
            	
            	$this->makeFileStructure($this->getTemplateById($template));
            }
            
            throw new ArrowTemplatesException(array (
    			"msg" => "Template already exists !.",
    			"mapping path" => $mappingPath
    		));            
            
        }catch(ArrowTemplatesException $ex){
            $keys = array_keys($this->configuration["templates"]);
            $newId = max($keys) + 1;
            $conf = $this->projectReference->getXMLConfig(ArrowProject::TEMPLATES_CONF);
            $template = $conf->templates->addChild("template");
            $el = explode("::", $mappingPath);
            $template->addAttribute("id", $newId);
            $template->addAttribute("name", $el[1]);
            $template->addAttribute("path", $el[0]);
            $template->addChild("requiredModels");       
            
            $file = ArrowProject::PATH.ArrowProject::TEMPLATES_CONF; 
            
            $dom = new DOMDocument('1.0');
            $dom->preserveWhiteSpace = false;
            $dom->formatOutput = true;
            $dom->loadXML($conf->asXml());

   
            
            file_put_contents( $file, $dom->saveXML());
            
            
            
            $conf = $this->projectReference->getXMLConfig(ArrowProject::TEMPLATES_SCHEMAS_CONF);
            
            $result = $conf->xpath("/schemas-root/schemas/schema[@id='$schemaId']/templateMembers");
          
            $result[0]->addChild("templateMember", $mappingPath);
           	
           //TODO Wykorzystac funckje z arrowProkject savexml
            $dom = new DOMDocument('1.0');
            $dom->preserveWhiteSpace = false;
            $dom->formatOutput = true;
            $dom->loadXML($conf->asXml());

            $file = ArrowProject::PATH.ArrowProject::TEMPLATES_SCHEMAS_CONF;
             
            file_put_contents( $file, $dom->saveXML());
            $this->refresh();
            ArrowSchemasList::getDefault($this->projectReference)->refresh();
            
            
            //FB::log($this->configuration);
            //exit();
            $template = $this->getTemplateByMappingPath($mappingPath);
            $this->makeFileStructure($template);
            
            
            
        
        }
        //$template = new ArrowTemplateDescriptor($this, $templateId, $registred["name"],  $this->sourcesDir . $registred["path"], $registred["description"]);
    
    }
	/**
	 * Makes file structure for template
	 *
	 * @param ArrowTemplateDescriptor $template
	 * @todo TODO wywalic calkiem i wlozyc do WEB GUI
	 */
	public function makeFileStructure( $template ){
		$blocks = $template->getSchema()->getBlocksNames();

		if(!file_exists($template->getPath()))
			mkdir( $template->getPath(), 0777, true );
			
		$file = $template->getPath()."/PageClass.php";
		if(!file_exists($file))
			file_put_contents( $file, "<?php\nclass ArrowPageClass extends ArrowSchemaClass{\npublic function createView(){\n}\n}\n?>");
		chmod($file, 0777);
		
		foreach($blocks as $block){
			$file = $template->getPath()."/".$block.".tpl";
			if(!file_exists($file))
				file_put_contents( $file, "" );
			
			chmod($file, 0777);
		}


		
	}
	
	
    public function refresh(){
        $confFile = ArrowProject::PATH. "/" . ArrowProject :: TEMPLATES_CONF;
        //$cacheFile = ArrowCacheProvider::getFileCache( $this, $confFile, array( "file_prefix" => $this->projectReference->getId()."_templates_structure" ) );
        //TODO clearstatcache  replacment 
        
        
        $cacheFile = ArrowCacheProvider::getFileCache( $this, $confFile, array( "file_prefix" => $this->projectReference->getId()."_templates_structure" ) );
        unlink($cacheFile);
        clearstatcache();
        $cacheFile = ArrowCacheProvider::getFileCache( $this, $confFile, array( "file_prefix" => $this->projectReference->getId()."_templates_structure" ) );
        
        
	    require $cacheFile;
	    $this->configuration = $cache; 
        
    }
	

}
?>
